package org.apache.james.mime4j.parser;

import java.io.IOException;
import java.util.BitSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.descriptor.BodyDescriptor;
import org.apache.james.mime4j.descriptor.DefaultBodyDescriptor;
import org.apache.james.mime4j.descriptor.MaximalBodyDescriptor;
import org.apache.james.mime4j.descriptor.MutableBodyDescriptor;
import org.apache.james.mime4j.io.LineReaderInputStream;
import org.apache.james.mime4j.io.MaxHeaderLimitException;
import org.apache.james.mime4j.io.MaxLineLimitException;
import org.apache.james.mime4j.util.ByteArrayBuffer;
import org.apache.james.mime4j.util.CharArrayBuffer;

public abstract class AbstractEntity
  implements EntityStateMachine
{
  private static final int T_IN_BODYPART = -2;
  private static final int T_IN_MESSAGE = -3;
  private static final BitSet fieldChars = new BitSet();
  protected final MutableBodyDescriptor body;
  protected final MimeEntityConfig config;
  private boolean endOfHeader;
  protected final int endState;
  private String field;
  private String fieldName;
  private String fieldValue;
  private final CharArrayBuffer fieldbuf;
  private int headerCount;
  private int lineCount;
  private final ByteArrayBuffer linebuf;
  protected final Log log;
  protected final BodyDescriptor parent;
  protected final int startState;
  protected int state;

  static
  {
    for (int i = 33; i <= 57; ++i)
      fieldChars.set(i);
    for (int j = 59; j <= 126; ++j)
      fieldChars.set(j);
  }

  AbstractEntity(BodyDescriptor paramBodyDescriptor, int paramInt1, int paramInt2, MimeEntityConfig paramMimeEntityConfig)
  {
    this.log = LogFactory.getLog(super.getClass());
    this.parent = paramBodyDescriptor;
    this.state = paramInt1;
    this.startState = paramInt1;
    this.endState = paramInt2;
    this.config = paramMimeEntityConfig;
    this.body = newBodyDescriptor(paramBodyDescriptor);
    this.linebuf = new ByteArrayBuffer(64);
    this.fieldbuf = new CharArrayBuffer(64);
    this.lineCount = 0;
    this.endOfHeader = false;
    this.headerCount = 0;
  }

  private void fillFieldBuffer()
    throws IOException, MimeException
  {
    if (this.endOfHeader);
    while (true)
    {
      int l;
      return;
      int i = this.config.getMaxLineLen();
      LineReaderInputStream localLineReaderInputStream = getDataStream();
      this.fieldbuf.clear();
      do
      {
        do
        {
          while (true)
          {
            while (true)
            {
              int j = this.linebuf.length();
              if ((i > 0) && (j + this.fieldbuf.length() >= i))
                throw new MaxLineLimitException("Maximum line length limit exceeded");
              if (j > 0)
                this.fieldbuf.append(this.linebuf, 0, j);
              this.linebuf.clear();
              if (localLineReaderInputStream.readLine(this.linebuf) != -1)
                break;
              monitor(Event.HEADERS_PREMATURE_END);
              this.endOfHeader = true;
            }
            int k = this.linebuf.length();
            if ((k > 0) && (this.linebuf.byteAt(k - 1) == 10))
              --k;
            if ((k > 0) && (this.linebuf.byteAt(k - 1) == 13))
              --k;
            if (k != 0)
              break;
            this.endOfHeader = true;
          }
          this.lineCount = (1 + this.lineCount);
        }
        while (this.lineCount <= 1);
        l = this.linebuf.byteAt(0);
      }
      while ((l == 32) || (l == 9));
    }
  }

  public static final String stateToString(int paramInt)
  {
    String str;
    switch (paramInt)
    {
    default:
      str = "Unknown";
    case -1:
    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9:
    case 10:
    case 11:
    case 12:
    case -2:
    case -3:
    }
    while (true)
    {
      while (true)
      {
        while (true)
        {
          while (true)
          {
            while (true)
            {
              while (true)
              {
                while (true)
                {
                  while (true)
                  {
                    while (true)
                    {
                      while (true)
                      {
                        while (true)
                        {
                          while (true)
                          {
                            while (true)
                            {
                              while (true)
                              {
                                while (true)
                                {
                                  while (true)
                                  {
                                    return str;
                                    str = "End of stream";
                                  }
                                  str = "Start message";
                                }
                                str = "End message";
                              }
                              str = "Raw entity";
                            }
                            str = "Start header";
                          }
                          str = "Field";
                        }
                        str = "End header";
                      }
                      str = "Start multipart";
                    }
                    str = "End multipart";
                  }
                  str = "Preamble";
                }
                str = "Epilogue";
              }
              str = "Start bodypart";
            }
            str = "End bodypart";
          }
          str = "Body";
        }
        str = "Bodypart";
      }
      str = "In message";
    }
  }

  protected void debug(Event paramEvent)
  {
    if (this.log.isDebugEnabled())
      this.log.debug(message(paramEvent));
  }

  public BodyDescriptor getBodyDescriptor()
  {
    switch (getState())
    {
    default:
      throw new IllegalStateException("Invalid state :" + stateToString(this.state));
    case -1:
    case 6:
    case 8:
    case 9:
    case 12:
    }
    return this.body;
  }

  protected abstract LineReaderInputStream getDataStream();

  public String getField()
  {
    switch (getState())
    {
    default:
      throw new IllegalStateException("Invalid state :" + stateToString(this.state));
    case 4:
    }
    return this.field;
  }

  public String getFieldName()
  {
    switch (getState())
    {
    default:
      throw new IllegalStateException("Invalid state :" + stateToString(this.state));
    case 4:
    }
    return this.fieldName;
  }

  public String getFieldValue()
  {
    switch (getState())
    {
    default:
      throw new IllegalStateException("Invalid state :" + stateToString(this.state));
    case 4:
    }
    return this.fieldValue;
  }

  protected abstract int getLineNumber();

  public int getState()
  {
    return this.state;
  }

  protected String message(Event paramEvent)
  {
    String str2;
    String str1 = "Line " + getLineNumber() + ": ";
    if (paramEvent == null)
      str2 = "Event is unexpectedly null.";
    while (true)
    {
      return str1 + str2;
      str2 = paramEvent.toString();
    }
  }

  protected void monitor(Event paramEvent)
    throws MimeException, IOException
  {
    if (this.config.isStrictParsing())
      throw new MimeParseEventException(paramEvent);
    warn(paramEvent);
  }

  protected MutableBodyDescriptor newBodyDescriptor(BodyDescriptor paramBodyDescriptor)
  {
    Object localObject;
    if (this.config.isMaximalBodyDescriptor())
      localObject = new MaximalBodyDescriptor(paramBodyDescriptor);
    while (true)
    {
      return localObject;
      localObject = new DefaultBodyDescriptor(paramBodyDescriptor);
    }
  }

  protected boolean parseField()
    throws IOException
  {
    int k;
    int l;
    int i2;
    int i = this.config.getMaxHeaderCount();
    if (this.endOfHeader)
      i2 = 0;
    while (true)
    {
      do
      {
        return i2;
        if (this.headerCount >= i)
          throw new MaxHeaderLimitException("Maximum header limit exceeded");
        fillFieldBuffer();
        this.headerCount = (1 + this.headerCount);
        int j = this.fieldbuf.length();
        if ((j > 0) && (this.fieldbuf.charAt(j - 1) == '\n'))
          j += -1;
        if ((j > 0) && (this.fieldbuf.charAt(j - 1) == '\r'))
          j += -1;
        this.fieldbuf.setLength(j);
        k = 1;
        this.field = this.fieldbuf.toString();
        l = this.fieldbuf.indexOf(58);
        if (l != -1)
          break label185;
        monitor(Event.INALID_HEADER);
        k = 0;
      }
      while (k == 0);
      this.body.addField(this.fieldName, this.fieldValue);
      i2 = 1;
    }
    label185: this.fieldName = this.fieldbuf.substring(0, l);
    int i1 = 0;
    while (true)
    {
      while (true)
      {
        if (i1 < this.fieldName.length())
        {
          if (fieldChars.get(this.fieldName.charAt(i1)))
            break;
          monitor(Event.INALID_HEADER);
          k = 0;
        }
        this.fieldValue = this.fieldbuf.substring(l + 1, this.fieldbuf.length());
      }
      ++i1;
    }
  }

  public String toString()
  {
    return super.getClass().getName() + " [" + stateToString(this.state) + "][" + this.body.getMimeType() + "][" + this.body.getBoundary() + "]";
  }

  protected void warn(Event paramEvent)
  {
    if (this.log.isWarnEnabled())
      this.log.warn(message(paramEvent));
  }
}